fix(mesh): authorize media-capture offers and guard unsolicited Claimed#189
Merged
Conversation
mrjeeves
force-pushed
the
claude/dtls-sdp-mitm-analysis-0xxnlt
branch
2 times, most recently
from
July 23, 2026 16:55
7f76aab to
3e6227e
Compare
Close two authorization gaps in the node engine. Media-source offers were unauthenticated. route_drive_plane() classifies only terminal/files/sites routes, so the offer gate's `authorized = route_drive_plane(route).is_none_or(...)` was unconditionally true for Display/Video/Audio. An offer whose source endpoint is a capability on this machine makes this node capture its own screen/camera/microphone and stream it to the offerer, yet any authenticated peer's offer was auto-accepted — unlike input (gated per frame) or terminal/files/sites (gated at admission). Add sender_may_source_media and screen the offer with it: a media-source offer this node would host is now refused unless the sender is owner/fleet, a CEC technician holding a live ScreenView consent grant (screen kinds only), or a person this device extended an explicit share to that lets them consume that media on that capability — the same owner/fleet -> CEC -> share layering may_drive already uses, reusing the canonical Grant::permits so capability pinning is honoured. Unsolicited OwnershipControl::Claimed took over the fleet. The Claimed arm added its sender to this device's fleet member list and signed roster and handed it the fleet key, without ever checking this node had sent that peer a Claim — while the sibling arms (Release, FleetKey) each guard their sender. Any authenticated peer could send an unsolicited Claimed and gain full control (input, shell, disk, clipboard, sites). Record a pending-claim when claim() sends a Claim, and honour Claimed only from a peer in that set, consuming the entry on use so a replayed or duplicate confirmation is ignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3oMk6B7NDM2SeQZUSz2ku
mrjeeves
force-pushed
the
claude/dtls-sdp-mitm-analysis-0xxnlt
branch
from
July 23, 2026 18:00
3e6227e to
ee690f0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes two authorization gaps in the node engine (
node/src/mesh.rs).1. Unauthenticated media capture (screen / camera / mic)
route_drive_plane()classifies only terminal/files/sites routes, so the offer gate'sauthorized = route_drive_plane(route).is_none_or(...)was unconditionallytrueforDisplay/Video/Audio. An offer whose source endpoint is a capability on this machine makes this node capture its own screen/camera/microphone and stream it to the offerer — yet any authenticated peer's offer was auto-accepted, unlike input (gated per-frame) or terminal/files/sites (gated at admission). The only Display/Video screen wascec_screen_offer_denied, which is inert for a non-CEC peer.Fix: add
sender_may_source_mediaand screen the offer with it. A media-source offer this node would host is refused unless the sender is owner/fleet, a CEC technician holding a liveScreenViewconsent grant (screen kinds only), or a person this device extended an explicit share to that lets them consume that media on that capability — the same owner/fleet → CEC → share layeringmay_drivealready uses, reusing the canonicalGrant::permitsso capability pinning is honoured. Legitimate flows (owner viewing a fleet member, a consented CEC technician, an explicit "Receive your screen" share) are unaffected. The receive/sink direction (a peer sharing their screen with me) is not gated — only offers that make this device source its own capture.2. Unsolicited
OwnershipControl::Claimedfleet takeoverThe
Claimedarm added its sender to this device's fleet member list and signed roster and handed it the fleet key, without ever checking this node had sent that peer aClaim— while the sibling arms (Release,FleetKey) each guard their sender. Both the member list and the roster are sourcessender_may_controltrusts, so any authenticated peer could send an unsolicitedClaimedand gain full control (input, shell, disk, clipboard, sites).Fix: record a pending-claim when
claim()sends aClaim, and honourClaimedonly from a peer in that set — consuming the entry on use, so a replayed or duplicate confirmation is ignored. Mirrors the per-sender guard the other ownership arms already apply.Testing
cargo test -p allmystuff-node --no-default-features— compilesmesh.rswith both fixes and passes all 95 unit tests. (The host media libs — ALSA / x11-xcb / v4l — aren't available in this environment; the changes are media-type-agnostic and live in non-feature-gated code, so they compile identically under the default host build, which swaps only the capture backends.)Notes
The CEC Support client consumes this engine by pinned release tag, so it picks up both fixes on the next
allmystuff-nodetag bump — no code change needed there.🤖 Generated with Claude Code
https://claude.ai/code/session_01J3oMk6B7NDM2SeQZUSz2ku
Generated by Claude Code